//
// Unihan Input Method
//
// Copyright © 2002-2007 Sun Wah Linux Ltd.
//
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//
// $Id: core.c 757 2007-05-10 08:19:31Z roger $
//

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <unihan_im.h>
#include <unihan_im_keycodes.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#include <SWTable.h>

#include "core.h"
#include "im_config.h"
#include "candidates.h"
#include "context.h"
#include "table.h"
#include "const.h"
#include "utils.h"
#include "shuangpin.h"
#include "punctuation.h"
#include "aux.h"

static int is_preedit_char(char c);

#define NUM_HOT_KEY 18

HotKey hotkey[NUM_HOT_KEY] = {
	{IM_SHIFT_MASK,	IM_VK_H,	KT_MOVE_CURSOR_FIRST},
	{IM_SHIFT_MASK,	IM_VK_J,	KT_MOVE_CURSOR_BEFORE},
	{IM_SHIFT_MASK,	IM_VK_K,	KT_MOVE_CURSOR_AFTER},
	{IM_SHIFT_MASK,	IM_VK_L,	KT_MOVE_CURSOR_LAST},
	{0,		IM_VK_UP,	KT_SEL_UP},
	{0,		IM_VK_DOWN,	KT_SEL_DOWN},
	{0,		IM_VK_LEFT,	KT_MOVE_CURSOR_BEFORE},
	{0,		IM_VK_RIGHT,	KT_MOVE_CURSOR_AFTER},
	{0,		IM_VK_HOME,	KT_MOVE_CURSOR_FIRST},
	{0,		IM_VK_END,	KT_MOVE_CURSOR_LAST},
	{0, 	IM_VK_COMMA,	KT_PAGE_UP},
	{0, 	IM_VK_PERIOD,	KT_PAGE_DOWN},
	{IM_SHIFT_MASK,	IM_VK_U,	KT_SEL_UP},
	{IM_SHIFT_MASK,	IM_VK_I,	KT_SEL_DOWN},
	{0,		IM_VK_EQUALS,	KT_PAGE_DOWN},
	{0,		IM_VK_MINUS,	KT_PAGE_UP},
	{0,		IM_VK_OPEN_BRACKET,	KT_PAGE_UP},
	{0,		IM_VK_CLOSE_BRACKET,	KT_PAGE_DOWN}
};

static int
is_preedit_char(char c)
{
	if (c >= 'a' && c <= 'z')
		return TRUE;
	if (c >= 'A' && c<= 'Z')
		return TRUE;
	return FALSE;
}

KeyType
get_key_type(UnihanIM *uim, IMKeyEvent *kev)
{
#if DEBUG
	fprintf(stderr, "table : get key type keyCode : %x\n", kev->keyCode);
#endif
	TableDesktopList *desktop = (TableDesktopList *)uim->desktopUserData;
	TableSession *session = (TableSession *)uim->sessionUserData;
	int i;

	if (session->context->sentence) {
		for (i=0; i<NUM_HOT_KEY; i++) {
			if ( (kev->modifier == hotkey[i].modifier) &&
				(kev->keyCode == hotkey[i].keyCode) )
				return hotkey[i].type;
		}
	}

	if (!kev->modifier) {
		if (kev->keyCode == IM_VK_SHIFT ||
			kev->keyCode == IM_VK_ALT ||
			kev->keyCode == IM_VK_CONTROL) {
			return KT_EAT;
		}
		/*if (kev->keyChar == '\'' ||
			kev->keyChar == ',' ||
			kev->keyChar == '.'
			) { understander ?? split a word which IM can't
			return KT_KICK;
		}*/
		if (kev->keyCode == IM_VK_ENTER) {
			if (!session->context->sentence) {
				return KT_PROPAGATE;
			}
			return KT_COMMIT;
		}
		if (kev->keyCode == IM_VK_SPACE) {
			if (!session->context->sentence) {
				return KT_PROPAGATE;
			}
			if (desktop->baseTable->header->hints & SHOW_AS_U_GO) {
				return KT_COMMIT;
			}
			//return KT_PAGE_DOWN;
			return KT_COMMIT;
		}
		if (kev->keyCode == IM_VK_BACK_SPACE) {
			if (!session->context->sentence) {
				return KT_PROPAGATE;
			} else {
				return KT_PREEDIT;
			}
		}
		if (is_punctuation(kev->keyChar)) {
			if (!session->context->sentence) {
				return KT_PUNCTUATION;
			} else {
				if (session->context->currNode && !session->context->currNode->kicked)
					return KT_KICK;
				else
					return KT_PREEDIT;
			}
		}
		if (is_preedit_char(kev->keyChar))
			return KT_PREEDIT;
		else
			return KT_PROPAGATE;
	}
	if (is_punctuation(kev->keyChar)) {
		if (!session->context->sentence) {
			return KT_PUNCTUATION;
		} else {
			if (!session->context->currNode->kicked)
				return KT_KICK;
			else
				return KT_PREEDIT;
		}
	}
	if (kev->modifier & IM_SHIFT_MASK) {
		if (is_preedit_char(kev->keyChar))
			return KT_PREEDIT;
		else
			return KT_PROPAGATE;
	}
	return KT_PROPAGATE;
}

int
key_event_cat(UnihanIM *uim, IMKeyEvent *kev)
{
#if DEBUG
	fprintf(stderr, "table : key_event_cat()\n");
#endif
	TableDesktopList *desktop = (TableDesktopList *)uim->desktopUserData;
	TableSession *session = (TableSession *)uim->sessionUserData;
	TableConfig *config = session->config;

	if (!config->ChMode) {
		//uim->m->key_press(kev);
		return FALSE;
	}

	if (is_punctuation(kev->keyChar)) {
		if (context_punctuation_stacked(session->context,
					kev,
					config)) {
			preedit_draw(uim);
			return TRUE;
		} else {
			return FALSE;
		}
	}

	kev->keyChar = tolower(kev->keyChar);

	if (context_key_stacked(session->context,
			kev,
			config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList,
			desktop->numPhraseTable)) {
		if (!session->context->sentence) {
			context_done(session->context);
			preedit_erase(uim);
			lookup_done(uim);
		} else {
			preedit_draw(uim);
			if (session->context->currNode) {
				if (!session->context->currNode->kicked) {
					lookup_draw(uim);
				} else {
					lookup_done(uim);
				}
			} else {
				lookup_done(uim);
			}
		}
		return TRUE;
	} else {
		beep(uim);
	}
	return TRUE;
}

int
key_punctuation(UnihanIM *uim, IMKeyEvent *kev)
{
	TableSession *session = (TableSession *)uim->sessionUserData;
	TableConfig *config = session->config;
	const char *punc;

	if (config->PuncMode) {
		punc = get_cn_punctuation(kev->keyChar);
		commit_string(uim, punc);
		return TRUE;
	}

	if (config->FullShape) {
		punc = get_fw_punctuation(kev->keyChar);
		commit_string(uim, punc);
		return TRUE;
	}
	return FALSE;
}

int
key_event_kick(UnihanIM *uim, IMKeyEvent *kev)
{
#if DEBUG
	fprintf(stderr, "table : key_event_kick()\n");
#endif
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_kick(session->context,
			kev,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		lookup_done(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

int
key_event_commit(UnihanIM *uim, IMKeyEvent *kev)
{
#if DEBUG
	fprintf(stderr, "table : key event commit\n");
#endif
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (session->context->sentence == NULL)
		return FALSE;

	if (!context_is_kicked(session->context)) {
		if (context_kick(session->context,
				kev,
				session->config,
				desktop->baseTable,
				desktop->adjuster,
				desktop->phraseTableList)) {
			preedit_draw(uim);
			lookup_done(uim);
		} else {
			beep(uim);
		}
	} else {
		commit(uim);
		context_done(session->context);
		preedit_erase(uim);
		lookup_done(uim);
	}
	return TRUE;
}

int
key_event_property(UnihanIM *uim, IMKeyEvent *kev)
{
#if DEBUG
	fprintf(stderr, "key_event_property()\n");
#endif
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	return TRUE;
}

int
page_up(UnihanIM *uim)
{
#if DEBUG
	fprintf(stderr, "table : page up()\n");
#endif
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_page_up(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		lookup_draw(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

int
page_down(UnihanIM *uim)
{
#if DEBUG
	fprintf(stderr, "table : page_down()\n");
#endif
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_page_down(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		lookup_draw(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

int
sel_up(UnihanIM *uim)
{
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_sel_up(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		lookup_draw(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

int
sel_down(UnihanIM *uim)
{
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_sel_down(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		lookup_draw(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

int
move_cursor_before(UnihanIM *uim)
{
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_move_cursor_before(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		if (session->context->currNode) {
			if (!session->context->currNode->kicked)
				lookup_draw(uim);
			else
				lookup_done(uim);
		} else {
			lookup_done(uim);
		}
	} else {
		beep(uim);
	}
	return TRUE;
}

int
move_cursor_after(UnihanIM *uim)
{
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_move_cursor_after(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		if (session->context->currNode) {
			if (!session->context->currNode->kicked)
				lookup_draw(uim);
			else
				lookup_done(uim);
		} else {
			lookup_done(uim);
		}
	} else {
		beep(uim);
	}
	return TRUE;
}

int
move_cursor_first(UnihanIM *uim)
{
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_move_cursor_first(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		lookup_done(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

int
move_cursor_last(UnihanIM *uim)
{
	TableDesktopList *desktop = uim->desktopUserData;
	TableSession *session = uim->sessionUserData;

	if (context_move_cursor_last(session->context,
			session->config,
			desktop->baseTable,
			desktop->adjuster,
			desktop->phraseTableList)) {
		preedit_draw(uim);
		if(!session->context->currNode->kicked)
			lookup_draw(uim);
		else
			lookup_done(uim);
	} else {
		beep(uim);
	}
	return TRUE;
}

// vi:ts=4:nowrap:cin:expandtab
